package com.mysteel.cart.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.mysteel.cart.feign.ProductFeignService;
import com.mysteel.cart.interceptor.CartInterceptor;
import com.mysteel.cart.service.CartService;
import com.mysteel.cart.vo.Cart;
import com.mysteel.cart.vo.CartItem;
import com.mysteel.cart.vo.SkuInfoVo;
import com.mysteel.cart.vo.UserInfoTo;
import com.mysteel.common.utils.R;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;

/**
 * ProjectName: mail
 * ClassName: CartServiceImpl
 * Description:
 * date: 2021/03/15/015 16:41
 *
 * @author xiaochao
 */
@Service
@Slf4j
public class CartServiceImpl implements CartService {

    @Autowired
    private StringRedisTemplate redisTemplate;

    private static final String CART_PREFIX = "mail:cart:";

    @Autowired
    private ProductFeignService productFeignService;

    @Autowired
    private ThreadPoolExecutor threadPoolExecutor;

    @Override
    public CartItem addToCart(Long skuId, Integer num) {
        BoundHashOperations<String, Object, Object> cartOps = getCartOps();

        String skuStr = (String) cartOps.get(skuId.toString());
        if (StringUtils.isNotBlank(skuStr)){
            // 购物车已有此商品，只需增加数量
            CartItem redisCartItem = JSONObject.parseObject(skuStr, CartItem.class);
            redisCartItem.setCount(redisCartItem.getCount() + num);
            cartOps.put(skuId.toString(),JSONObject.toJSONString(redisCartItem));
            return redisCartItem;
        }

        CartItem cartItem = new CartItem();
        CompletableFuture<Void> skuInfoFuture = CompletableFuture.runAsync(() -> {
            // 远程查询当前sku的信息
            R skuInfoFeign = productFeignService.info(skuId);
            SkuInfoVo skuInfo = skuInfoFeign.getData("skuInfo", new TypeReference<SkuInfoVo>() {
            });
            cartItem.setSkuId(skuInfo.getSkuId());
            cartItem.setCount(num);
            cartItem.setImg(skuInfo.getSkuDefaultImg());
            cartItem.setTitle(skuInfo.getSkuTitle());
            cartItem.setPrice(skuInfo.getPrice());
        }, threadPoolExecutor);

        CompletableFuture<Void> skuSaleAttrFuture = CompletableFuture.runAsync(() -> {
            // 获取sku销售属性
            List<String> skuSaleAttrValue = productFeignService.getSkuSaleAttrValueById(skuId);
            cartItem.setSkuAttr(skuSaleAttrValue);
        }, threadPoolExecutor);

        // 异步获取sku信息结束
        try {
            CompletableFuture.allOf(skuInfoFuture,skuSaleAttrFuture).get();
        } catch (Exception e) {
         log.error("异步获取sku信息出错：{}",e);
        }

        // 将购物项信息存入redis
        String jsonStr = JSONObject.toJSONString(cartItem);
        cartOps.put(skuId.toString(),jsonStr);

        return cartItem;
    }

    @Override
    public CartItem getCartItemBySkuId(Long skuId) {
        BoundHashOperations<String, Object, Object> cartOps = getCartOps();
        String skuStr = (String) cartOps.get(skuId.toString());
        return JSONObject.parseObject(skuStr,CartItem.class);
    }

    @Override
    public Cart getUserCart() {
        Cart cart = new Cart();
        UserInfoTo userInfoTo = CartInterceptor.threadLocal.get();
        // 先查询零时购物车中是否有数据
        String tempCartKey = CART_PREFIX + userInfoTo.getUserKey();
        List<CartItem> tempCartItem = getCartItemByKey(tempCartKey);
        if (userInfoTo.getUserId() != null){
            // 用户已登录
            if (!CollectionUtils.isEmpty(tempCartItem)){
                // 将临时购物车的数据加入用户购物车
                for (CartItem cartItem : tempCartItem) {
                    addToCart(cartItem.getSkuId(),cartItem.getCount());
                }
                // 删除零时购物车的数据
                clearCartByKey(tempCartKey);
            }
            // 重新获取用户购物车的数据
            String cartKey = CART_PREFIX + userInfoTo.getUserId();
            List<CartItem> cartItem = getCartItemByKey(cartKey);
            if (CollectionUtils.isEmpty(cartItem)){
                cart.setCartItems(new ArrayList<>(0));
                return cart;
            }
            cart.setCartItems(cartItem);
            return cart;
        }

        // 用户未登录，返回用户零时购物车
        if (!CollectionUtils.isEmpty(tempCartItem)){
            cart.setCartItems(tempCartItem);
            return cart;
        }
        cart.setCartItems(new ArrayList<>(0));
        return cart;
    }

    /**
     * 获取要操作的购物车
     * @return
     */
    private BoundHashOperations<String, Object, Object> getCartOps() {
        UserInfoTo userInfoTo = CartInterceptor.threadLocal.get();
        String cartKey = "";
        if (userInfoTo.getUserId() != null){
            // 用户已登录
            cartKey = CART_PREFIX + userInfoTo.getUserId();
        }else {
            cartKey = CART_PREFIX + userInfoTo.getUserKey();
        }

        return redisTemplate.boundHashOps(cartKey);
    }

    /**
     * 通过key获取购物车数据
     * @param key
     * @return
     */
    private List<CartItem> getCartItemByKey(String key){
        BoundHashOperations<String, Object, Object> hashOps = redisTemplate.boundHashOps(key);
        List<Object> values = hashOps.values();
        if (!CollectionUtils.isEmpty(values)){
            return values.stream().map(obj -> {
                String jsonObj = (String) obj;
                return JSONObject.parseObject(jsonObj, CartItem.class);
            }).collect(Collectors.toList());
        }
        return null;
    }

    /**
     * 清空购物车数据
     * @param key
     */
    @Override
    public void clearCartByKey(String key){
        redisTemplate.delete(key);
    }

    @Override
    public void checkItem(String skuIds, Integer check) {
        BoundHashOperations<String, Object, Object> cartOps = getCartOps();
        if (StringUtils.isBlank(skuIds)){
            return;
        }
        List<String> skuIdList = Arrays.asList(skuIds.split(","));
        if (CollectionUtils.isEmpty(skuIdList)){
            return;
        }
        for (String skuId : skuIdList) {
            CartItem cartItemBySkuId = getCartItemBySkuId(Long.valueOf(skuId));
            cartItemBySkuId.setCheck(check == 1);
            String json = JSONObject.toJSONString(cartItemBySkuId);
            cartOps.put(skuId,json);
        }

    }

    /**
     * 改变购物车中的购物项的数量
     * @param skuId
     * @param count
     */
    @Override
    public void changeItemCount(Long skuId, Integer count) {
        CartItem cartItemBySkuId = getCartItemBySkuId(skuId);
        cartItemBySkuId.setCount(count);
        BoundHashOperations<String, Object, Object> cartOps = getCartOps();
        cartOps.put(skuId.toString(),JSONObject.toJSONString(cartItemBySkuId));
    }

    /**
     * 删除购车中的购物项
     * @param skuId
     */
    @Override
    public void deleteItemBySkuId(Long skuId) {
        BoundHashOperations<String, Object, Object> cartOps = getCartOps();
        cartOps.delete(skuId.toString());
    }

    @Override
    public List<CartItem> getCurrentUserCartItems() {
        UserInfoTo userInfoTo = CartInterceptor.threadLocal.get();
        if (userInfoTo.getUserId() == null){
            return new ArrayList<>(0);
        }
        String cartKey = CART_PREFIX + userInfoTo.getUserId();
        List<CartItem> cartItemByKey = getCartItemByKey(cartKey);
        if (CollectionUtils.isEmpty(cartItemByKey)){
            return new ArrayList<>(0);
        }
        cartItemByKey = cartItemByKey.stream()
                .filter(CartItem::getCheck)
                .peek(item -> {
                    // 查询商品的最新价格
                    BigDecimal priceBySkuId = productFeignService.getPriceBySkuId(item.getSkuId());
                    item.setPrice(priceBySkuId);
                })
                .collect(Collectors.toList());
        return cartItemByKey;
    }
}
